package com.baizhi.utils;

import cn.hutool.core.util.ObjectUtil;
import com.baizhi.dto.RedisData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.time.LocalDateTime;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

public class CacheClient {
    @Autowired
    private RedisTemplate redisTemplate;
    //线程池对象
    private ExecutorService threadPool = new ThreadPoolExecutor(10,10,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(50));

    private <R,T> R queryWithLogicalExpire(String redisCachePrefix, T t, String redisLockPrefix, Long ttl, Function<T,R> function){
        String key =  RedisConstants.CACHE_SHOP_KEY+t;
        RedisData redisData = (RedisData) redisTemplate.opsForValue().get(key);
        if(ObjectUtil.isEmpty(redisData)){
            return null;
        }
        if(LocalDateTime.now().isAfter(redisData.getExpireTime())){
            String lockKey = redisLockPrefix + t;
            Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey,1,ttl,TimeUnit.MINUTES);
            if (success){
                threadPool.submit(()->{
                    try{
                        R newObj = function.apply(t);
                        RedisData rd = new RedisData(LocalDateTime.now().plusMinutes(ttl),newObj);
                        redisTemplate.opsForValue().set(key,rd);
                    }finally {
                        redisTemplate.delete(lockKey);
                    }
                });
            }
        }
        return (R)redisData.getData();
    }
    public<R,T> R queryWithMutex(T t,String redisPrefix,Function<T,R> function,Long ttl,TimeUnit unit){
        String key = redisPrefix+t;
        R r = (R) redisTemplate.opsForValue().get(key);
        if(ObjectUtil.isNotEmpty(r)){
            return r;
        }
        synchronized (this){
            r= (R)redisTemplate.opsForValue().get(key);
            if (ObjectUtil.isNotEmpty(r)){
                return r;
            }
            r = function.apply(t);
            if(ObjectUtil.isEmpty(r)){
                return null;
            }
            redisTemplate.opsForValue().set(key,r,ttl,unit);
            return r;
        }
    }
}
